package com.ruoyi.model.manager.service.impl;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.exception.file.FileUploadException;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.file.FileUtils;
import com.ruoyi.common.utils.python.PythonUtil;
import com.ruoyi.model.manager.domain.ModelManager;
import com.ruoyi.model.manager.domain.TableNode;
import com.ruoyi.model.manager.input.ModelManagerInput;
import com.ruoyi.model.manager.mapper.ModelManagerMapper;
import com.ruoyi.model.manager.output.ModelManagerOutput;
import com.ruoyi.model.manager.service.IModelManagerService;
import com.ruoyi.model.manager.service.ITableService;
import com.ruoyi.model.records.domain.ModelRecords;
import com.ruoyi.model.records.mapper.ModelRecordsMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;

/**
 * 模型管理Service业务层处理
 * 
 * @author ruoyi
 * @date 2024-11-08
 */
@Slf4j
@Service
public class ModelManagerServiceImpl extends ServiceImpl<ModelManagerMapper, ModelManager> implements IModelManagerService //修改
{
    @Autowired
    private ModelManagerMapper modelManagerMapper;

    @Resource
    private ITableService tableServiceImpl;

    @Resource
    private ModelRecordsMapper modelRecordsMapper;

    @Value("${python.path}")
    private String pythonPath;

    @Value("${json.path}")
    private String jsonPath;

    /**
     * 查询模型管理
     * 
     * @param id 模型管理主键
     * @return 模型管理
     */
    @Override
    public ModelManager selectModelManagerById(Long id)
    {
        return modelManagerMapper.selectModelManagerById(id);
    }

    /**
     * 查询模型管理列表
     * 
     * @param modelManager 模型管理
     * @return 模型管理
     */
    @Override
    public List<ModelManager> selectModelManagerList(ModelManager modelManager)
    {
        return modelManagerMapper.selectModelManagerList(modelManager);
    }

    /**
     * 新增模型管理
     * 
     * @param modelManager 模型管理
     * @return 结果
     */
    @Override
    public int insertModelManager(ModelManager modelManager)
    {

        return modelManagerMapper.insertModelManager(modelManager);
    }

    /**
     * 修改模型管理
     * 
     * @param modelManager 模型管理
     * @return 结果
     */
    @Override
    public int updateModelManager(ModelManager modelManager)
    {

        return modelManagerMapper.updateModelManager(modelManager);
    }

    /**
     * 批量删除模型管理
     * 
     * @param ids 需要删除的模型管理主键
     * @return 结果
     */
    @Override
    public int deleteModelManagerByIds(Long[] ids)
    {
        return modelManagerMapper.deleteModelManagerByIds(ids);
    }

    /**
     * 删除模型管理信息
     * 
     * @param id 模型管理主键
     * @return 结果
     */
    @Override
    public int deleteModelManagerById(Long id)
    {
        return modelManagerMapper.deleteModelManagerById(id);
    }



    /**
     * 预览模型结果 只取十条数据
     *
     * 1、根据传进来的tables查询出对应的10条数据
     * 2、生成json文件
     * 3、调用python脚本进行数据处理
     * 4、读取结果文件返回
     *
     * @return
     */
    @Override
    public Object previewModel(ModelManagerInput input) {
        if (input.getTables().isEmpty()) {
            throw new ServiceException("请选择数据表");
        }
        if (StringUtils.isEmpty(input.getName())) {
            throw new ServiceException("请输入模型名称");
        }
        if (StringUtils.isEmpty(input.getMethod())) {
            throw new ServiceException("请选择模型方法");
        }
        String pythonCode = input.getPythonCode();
        if (StringUtils.isEmpty(pythonCode)) {
            throw new ServiceException("请输入python代码");
        }
        // 构建Python脚本文件的完整路径并写入Python代码

        String pythonModelUUID = UUID.randomUUID().toString();//预览时临时生成需要删除

        String pythonPreviewPath = pythonPath + "preview" + File.separator + pythonModelUUID + ".py";
        // 确保目标路径存在
        File pythonPreviewFile = new File(pythonPreviewPath);
        try {
            Files.createDirectories(Paths.get(pythonPreviewFile.getParent()));
        } catch (IOException e) {
            throw new ServiceException("生成 Python 文件失败");
        }

        try (BufferedWriter writer = new BufferedWriter(new FileWriter(pythonPreviewPath))) {
            writer.write(pythonCode);
        } catch (IOException e) {
            throw new ServiceException("写入Python文件时发生错误: " + e.getMessage());
        }

        // 获取数据
        List<JSONObject> tableColumnsData = tableServiceImpl.getTableColumnsData(input.getTables(), 10);

        // 定义 JSON 文件路径
        String jsonFilePath = jsonPath + UUID.randomUUID() + ".json";

        // 生成 JSON 文件
        try (FileWriter file = new FileWriter(jsonFilePath)) {
            file.write(JSON.toJSONString(tableColumnsData));
            file.flush();
        } catch (IOException e) {
            log.error("生成 JSON 文件失败: ", e);
            throw new RuntimeException("生成 JSON 文件失败");
        }
        List<String> callPythonArgs = new ArrayList<>();
        callPythonArgs.add("python");
        callPythonArgs.add(pythonPath + "main.py");
        callPythonArgs.add(pythonModelUUID);
        callPythonArgs.add(input.getMethod());
        callPythonArgs.add(jsonFilePath);

        List<String> results = PythonUtil.callPython(callPythonArgs.toArray(new String[0]));

        log.info("python执行结果:{}", results);
        for (String result : results) {
            if (result.endsWith(".json")) {
                // 读取 JSON 文件
                try (FileReader fileReader = new FileReader(result)) {

                    BufferedReader bufferedReader = new BufferedReader(fileReader);


                        StringBuilder content = new StringBuilder();
                        String line;
                        while ((line = bufferedReader.readLine()) != null) {
                            content.append(line);
                        }
                    log.info("读取的 JSON 内容: {}", content);
                    try {
                        return JSON.parse(content.toString());
                    } catch (Exception e) {
                        return content;
                    }
                } catch (IOException e) {
                    log.error("读取 JSON 文件失败: ", e);
                    throw new ServiceException("读取 JSON 文件失败");
                }finally {

                    FileUtils.deleteFile(jsonFilePath);
                    FileUtils.deleteFile(result);
                    FileUtils.deleteFile(pythonPreviewPath);
                }


            }
        }
        return results;
    }

    /**
     * 导入python文件
     *
     * @param file
     * @return
     */
    @Override
    public ModelManagerOutput importPythonFile(MultipartFile file) {

        ModelManagerOutput output = new ModelManagerOutput();

        try {
            // 检查文件是否为空
            if (file.isEmpty()) {
                log.error("文件为空.");
                throw new FileUploadException("文件为空.");
            }

            // 读取文件内容
            try (InputStream inputStream = file.getInputStream();
                 ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
                byte[] buffer = new byte[1024];
                int length;
                while ((length = inputStream.read(buffer)) != -1) {
                    outputStream.write(buffer, 0, length);
                }
                String fileContent = new String(outputStream.toByteArray(), StandardCharsets.UTF_8);

                // 设置输出对象的属性
                output.setPythonCode(fileContent);
                output.setMethods(PythonUtil.getPythonMethodNamesByContent(fileContent));
            }

            return output;
        } catch (FileUploadException | IOException e) {
            log.error("文件上传失败", e);

        }

        return null;
    }

    /**
     * @param input
     * @return
     */
    @Override
    public int save(ModelManagerInput input) {

        input.setCreateBy(SecurityUtils.getUsername());
        Integer i = this.modelManagerMapper.selectCount(new LambdaQueryWrapper<ModelManager>()
                .eq(ModelManager::getName, input.getName()));
        log.info("重复数据：{}", i);
        //TODO 去重，唯一性校验
        if (i > 0) {
            throw new ServiceException("模型名称重复");
        }

        String pythonCode = input.getPythonCode();
        if (StringUtils.isEmpty(pythonCode)) {
            throw new ServiceException("请输入python代码");
        }
        String pythonSavePath = pythonPath + "save" + File.separator + input.getName() + ".py";
        // 确保目标路径存在
        File pythonSaveFile = new File(pythonSavePath);
        try {
            Files.createDirectories(Paths.get(pythonSaveFile.getParent()));
        } catch (IOException e) {
            throw new RuntimeException("生成 JSON 文件失败");
        }

        try (FileWriter file = new FileWriter(pythonSavePath)) {
            file.write(pythonCode);
            file.flush();
        } catch (IOException e) {
            log.error("生成 Python 文件失败: ", e);
            throw new RuntimeException("生成 Python 文件失败");
        }
        ModelManager modelManager = new ModelManager();
        BeanUtils.copyProperties(input, modelManager);
        modelManager.setInputParams(JSON.toJSONString(input.getTables()));
        modelManager.setPath(pythonSavePath);
        modelManager.setStatus(0);

        return this.insertModelManager(modelManager);
    }

    /**
     * 1、移除模型文件
     * 2、重新创建
     * 3、更新数据库
     * @param input
     * @return
     */
    @Override
    public int update(ModelManagerInput input) {
        input.setUpdateBy(SecurityUtils.getUsername());

        // 源文件路径
        String sourceFilePath = input.getPath();
        // 目标文件路径
        String destinationFilePath = pythonPath + "trash" + File.separator + System.currentTimeMillis()+"_"+input.getName() + ".py";

        try {
            // 创建 Path 对象
            Path sourcePath = Paths.get(sourceFilePath);
            Path destinationPath = Paths.get(destinationFilePath);
            // 确保目标目录存在
            Path destinationDir = destinationPath.getParent();
            if (destinationDir != null) {
                Files.createDirectories(destinationDir);
            }
            // 移动文件
            Files.move(sourcePath, destinationPath, StandardCopyOption.REPLACE_EXISTING);
            String pythonCode = input.getPythonCode();
            if (StringUtils.isEmpty(pythonCode)) {
                throw new ServiceException("请输入python代码");
            }
            String pythonSavePath = pythonPath + "save" + File.separator + input.getName() + ".py";
            // 确保目标路径存在
            File pythonSaveFile = new File(pythonSavePath);
            try {
                Files.createDirectories(Paths.get(pythonSaveFile.getParent()));
            } catch (IOException e) {
                throw new RuntimeException("生成 JSON 文件失败");
            }

            try (FileWriter file = new FileWriter(pythonSavePath)) {
                file.write(pythonCode);
                file.flush();
            } catch (IOException e) {
                log.error("生成 Python 文件失败: ", e);
                throw new ServiceException("生成 Python 文件失败");
            }
            log.info("文件移动成功 from {} to {}", sourceFilePath, destinationFilePath);
            ModelManager modelManager = new ModelManager();
            BeanUtils.copyProperties(input, modelManager);
            modelManager.setInputParams(JSON.toJSONString(input.getTables()));
            modelManager.setStatus(0);

            return this.updateModelManager(modelManager);
        } catch (IOException e) {
            log.error("文件移动失败: ", e);

            throw new ServiceException("生成 Python 文件失败");
        }
    }

    /**
     * @param id
     * @return
     */
    @Override
    public ModelManagerOutput selectModelManagerOutputById(Long id) {

        ModelManager modelManager = this.modelManagerMapper.selectModelManagerById(id);
        if (modelManager != null) {
            try {
                ModelManagerOutput output = new ModelManagerOutput();
                BeanUtils.copyProperties(modelManager, output);
                String pythonCode = FileUtils.readFileToString(new File(modelManager.getPath()), StandardCharsets.UTF_8);
                output.setPythonCode(pythonCode);
                output.setMethods(PythonUtil.getPythonMethodNamesByContent(pythonCode));
                output.setTables(JSON.parseArray(modelManager.getInputParams(), TableNode.class));
                return output;
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        return null;
    }

    /**
     * @param id
     * @return
     */
    @Override
    public void runModel(long id) {

        ModelRecords record = new ModelRecords();
        record.setStartTime(new Date());
        record.setModelId(id);


        ModelManager model = this.modelManagerMapper.selectModelManagerById(id);

        if (ObjectUtils.isEmpty(model)) {
            record.setStatus(0);
            record.setResult("模型不存在");
            record.setEndTime(new Date());
            modelRecordsMapper.insertModelRecords(record);
            log.error("模型不存在");
            throw new ServiceException("模型不存在");
        }

        if (!StringUtils.isEmpty(model.getName())) {
            record.setModelName(model.getName());
        }
        if (model.getStatus() == 1) {
            log.error("模型正在分析中");
            throw new ServiceException("模型正在分析中");
        }
        File pythonFile = new File(model.getPath()); //python存放路径
        if (!pythonFile.exists()) {
            record.setStatus(0);
            record.setResult("python文件不存在");
            record.setEndTime(new Date());
            modelRecordsMapper.insertModelRecords(record);
            log.error("python文件不存在");
            throw new ServiceException("python文件不存在");
        }

        List<JSONObject> tableColumnsData = tableServiceImpl.getTableColumnsData(JSON.parseArray(model.getInputParams(), TableNode.class), 1000);//分析数据源

        String jsonFilePath = jsonPath + UUID.randomUUID() + ".json";//数据生成临时json文件传递

        // 生成 JSON 文件
        try (FileWriter jsonFile = new FileWriter(jsonFilePath)) {
            jsonFile.write(JSON.toJSONString(tableColumnsData));
            jsonFile.flush();
        } catch (IOException e) {
            log.error("生成 JSON 文件失败: ", e);
            record.setStatus(0);
            record.setResult("分析结果获取错误");
            record.setEndTime(new Date());
            modelRecordsMapper.insertModelRecords(record);
            log.error("生成 JSON 文件失败");
            throw new RuntimeException("生成 JSON 文件失败");
        }
        List<String> callPythonArgs = new ArrayList<>();
        callPythonArgs.add("python");
        callPythonArgs.add(pythonPath + "main.py");
        callPythonArgs.add(model.getName());
        callPythonArgs.add(model.getMethod());
        callPythonArgs.add(jsonFilePath);

        model.setStatus(1);
        this.modelManagerMapper.updateModelManager(model);
        List<String> results = PythonUtil.callPython(callPythonArgs.toArray(new String[0]));
        log.info("模型{}运行结果{}", model.getName(), results);
        log.info("python执行结果:{}", results);
        for (String result : results) {
            if (result.endsWith(".json")) {
                // 读取 JSON 文件
                try (FileReader fileReader = new FileReader(result)) {

                    BufferedReader bufferedReader = new BufferedReader(fileReader);

                    StringBuilder content = new StringBuilder();
                    String line;
                    while ((line = bufferedReader.readLine()) != null) {
                        content.append(line);
                    }
                    log.info("读取的 JSON 内容: {}", content);
                    record.setStatus(1);
                    record.setResult(content.toString());
                    record.setEndTime(new Date());
                    modelRecordsMapper.insertModelRecords(record);
                } catch (IOException e) {
                    record.setStatus(0);
                    record.setResult("分析结果获取错误");
                    record.setEndTime(new Date());
                    modelRecordsMapper.insertModelRecords(record);
                    log.error("读取 JSON 文件失败: ", e);
                    throw new ServiceException("读取 JSON 文件失败");
                }finally {
                    FileUtils.deleteFile(jsonFilePath);
                    FileUtils.deleteFile(result);
                }
            }
        }
        model.setStatus(0);
        this.modelManagerMapper.updateModelManager(model);
    }


}
